package org.hxzon.cyclone;

//core.h
//三维向量
public class Vector3 {
    public static final Vector3 GRAVITY = new Vector3(0, -9.81, 0);
    public static final Vector3 HIGH_GRAVITY = new Vector3(0, -19.62, 0);
    public static final Vector3 UP = new Vector3(0, 1, 0);
    public static final Vector3 RIGHT = new Vector3(1, 0, 0);
    public static final Vector3 OUT_OF_SCREEN = new Vector3(0, 0, 1);
    public static final Vector3 X = new Vector3(0, 1, 0);
    public static final Vector3 Y = new Vector3(1, 0, 0);
    public static final Vector3 Z = new Vector3(0, 0, 1);

    public double x;

    public double y;

    public double z;

    /** Padding to ensure 4 word alignment. */
    //private double pad;

    //=========================
    public Vector3() {
        this(0, 0, 0);
    }

    public Vector3(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    //[i]
    public double get(int i) {
        if (i == 0) {
            return x;
        }
        if (i == 1) {
            return y;
        }
        return z;
    }

    public void set(int i, double value) {
        if (i == 0) {
            x = value;
        } else if (i == 1) {
            y = value;
        } else {
            z = value;
        }
    }

    //向量相加
    public void addUpdate(Vector3 v) {
        x += v.x;
        y += v.y;
        z += v.z;
    }

    public Vector3 add(Vector3 v) {
        return new Vector3(x + v.x, y + v.y, z + v.z);
    }

    //向量相减
    public void minusUpdate(Vector3 v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
    }

    public Vector3 minus(Vector3 v) {
        return new Vector3(x - v.x, y - v.y, z - v.z);
    }

    //标量相乘，向量缩放
    public void multiUpdate(double value) {
        x *= value;
        y *= value;
        z *= value;
    }

    public Vector3 multi(double value) {
        return new Vector3(x * value, y * value, z * value);
    }

    //分量积，各分量相乘，
    public void componentProductUpdate(Vector3 vector) {
        x *= vector.x;
        y *= vector.y;
        z *= vector.z;
    }

    public Vector3 componentProduct(Vector3 vector) {
        return new Vector3(x * vector.x, y * vector.y, z * vector.z);
    }

    public void vectorProductUpdate(Vector3 vector) {
        x = y * vector.z - z * vector.y;
        y = z * vector.x - x * vector.z;
        z = x * vector.y - y * vector.x;
    }

    //向量积，叉积，外积，结果向量与两个原向量垂直
    //本书使用 % 表示
    public Vector3 vectorProduct(Vector3 vector) {
        Vector3 result = this.copy();
        result.vectorProductUpdate(vector);
        return result;
    }

    //分量积的和，点积，内积，数量积，标量积，投影量值,*?
    public double scalarProduct(Vector3 vector) {
        return x * vector.x + y * vector.y + z * vector.z;
    }

    //
    public void addScaledVector(Vector3 vector, double scale) {
        x += vector.x * scale;
        y += vector.y * scale;
        z += vector.z * scale;
    }

    //===========================================
    //向量长度
    public double magnitude() {
        return Util.realSqrt(x * x + y * y + z * z);
    }

    /** Gets the squared magnitude of this vector. */
    public double squareMagnitude() {
        return x * x + y * y + z * z;
    }

    /** Limits the size of the vector to the given maximum. */
    public void trim(double size) {
        if (squareMagnitude() > size * size) {
            normalise();
            x *= size;
            y *= size;
            z *= size;
        }
    }

    /** Turns a non-zero vector into a vector of unit length. */
    public void normalise() {
        double magnitude = magnitude();
        if (magnitude > 0) {
            double s = ((double) 1) / magnitude;
            x *= s;
            y *= s;
            z *= s;
        }
    }

    /** Returns the normalised version of a vector. */
    public Vector3 unit() {
        Vector3 result = copy();
        result.normalise();
        return result;
    }

    /** Checks if the two vectors have identical components. */
    public boolean isEqual(Vector3 other) {
        return x == other.x && y == other.y && z == other.z;
    }

    /** Checks if the two vectors have non-identical components. */
    public boolean isNotEqual(Vector3 other) {
        return !isEqual(other);
    }

    /**
     * Checks if this vector is component-by-component less than
     * the other.
     *
     * @note This does not behave like a single-value comparison:
     * !(a < b) does not imply (b >= a).
     */
    public boolean isSmaller(Vector3 other) {
        return x < other.x && y < other.y && z < other.z;
    }

    /**
     * Checks if this vector is component-by-component less than
     * the other.
     *
     * @note This does not behave like a single-value comparison:
     * !(a < b) does not imply (b >= a).
     */
    public boolean isBigger(Vector3 other) {
        return x > other.x && y > other.y && z > other.z;
    }

    /**
     * Checks if this vector is component-by-component less than
     * the other.
     *
     * @note This does not behave like a single-value comparison:
     * !(a <= b) does not imply (b > a).
     */
    public boolean isSmallerOrEqual(Vector3 other) {
        return x <= other.x && y <= other.y && z <= other.z;
    }

    /**
     * Checks if this vector is component-by-component less than
     * the other.
     *
     * @note This does not behave like a single-value comparison:
     * !(a <= b) does not imply (b > a).
     */
    public boolean isBiggerOrEqual(Vector3 other) {
        return x >= other.x && y >= other.y && z >= other.z;
    }

    /** Zero all the components of the vector. */
    public void clear() {
        x = y = z = 0;
    }

    /** Flips all the components of the vector. */
    //public void invert() {
    public void invertUpdate() {
        x = -x;
        y = -y;
        z = -z;
    }

    public Vector3 copy() {
        return new Vector3(x, y, z);
    }

}
